/* @(#)common.h
 * Time-stamp: <2008-10-25 19:54:10 root>
 * Copyright 2008 Julian Qian
 * Author: root@localhost.localdomain
 * Version: $Id: common.h,v 0.0 2008/09/27 13:43:19 root Exp $
 * Keywords: 
 */

#ifndef _COMMON_H
#define _COMMON_H 1

#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <string.h>
#include <errno.h>
#include <time.h>
#include <utmpx.h>
#include <sys/msg.h>
#include <sys/shm.h>
#include <sys/sem.h>
#include <sys/socket.h>
#include <sys/signal.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <unistd.h>
#include <fcntl.h>
#include <netdb.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <math.h>
#include <getopt.h>
#include <syslog.h>
#include <pthread.h>

#include <mysql.h>

#include "hashtable.h"
#include "hashtable_utility.h"
#include "hashtable_itr.h"

#ifndef NULL
#define NULL 0
#endif

#ifndef FALSE
#define FALSE 0
#endif

#ifndef TRUE
#define TRUE 1
#endif

#define MAXBUF 4096

#ifndef TRACE_FILE
#define TRACE_FILE "./trace"
#endif

/* Following shortens all the type casts of pointer arguments */
#define	SA	struct sockaddr

#define	FILE_MODE	(S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH)
					/* default file access permissions for new files */
#define	DIR_MODE	(FILE_MODE | S_IXUSR | S_IXGRP | S_IXOTH)
					/* default permissions for new directories */

/* Miscellaneous constants */
#define	MAXLINE		4096	/* max text line length */
#define	MAXSOCKADDR  128	/* max socket address structure size */
#define	BUFFSIZE	8192	/* buffer size for reads and writes */
#define PHONE_SIZE 14   /* mobile phone number length */
#define IP_ANON_SIZE 16 /* ip address length */

#define MAXLEN 50
#define HEART_MAX 10000
#define HEART_HOLDER 1

#define SHM_ESMS_SIZE 5000 /* ws_alarm_receive */
#define SHM_DEVICE "/dev/shm/ehome"

#define SERVER_PORT 6800
#define CLIENT_PORT 6800

#define DISPATCH_DEFENSE 1
#define DISPATCH_HEART 2

/* alarm defense define */
/* ################ 11th byte ################ */
#define SPEC1 0x6C
#define SPEC2 0xD0

#define SPEC_1 1
#define SPEC_2 2
#define SPEC_0 0

/* ################ 15th byte ################ */
#define CLI_RESET 0x0
#define CLI_ALARM 0x2
#define CLI_TIMER 0x4
#define CLI_DEFEN 0x5

#define SER_RESET 0x1
#define SER_ALARM 0x3
#define SER_DEFEN 0x6

#define SER_UPDATE 0x7
#define CLI_UPDATE 0x8

/* ################ 16th byte ################ */
/* 0x02 */
#define ALARM_MANUA 0x01
#define ALARM_DOORR 0x02
#define ALARM_INFRA 0x04

#define ALARM_MANUA_USER 1
#define ALARM_DOORR_USER 2
#define ALARM_INFRA_USER 3

/* 0x05 */
#define CTRL_DEFEN 0x30
#define CTRL_UNDEF 0x00

/* 0x07 */
#define USER_DEFEN 0x30
#define USER_UNDEF 0x00
#define USER_NULL 0

/* phone msg from user */
#define USER_DEFEN_MSG "bf"
#define USER_UNDEF_MSG "cf"


/* ################ these status ################ */
#define STAT_NULLL 0 /* undefined */
#define STAT_RESET 1 /* device init .. */
#define STAT_TIMER 2 /* normal poll query, every 4 min */
#define STAT_DEFEN 3 /* defense by tele controller*/
#define STAT_UNDEF 4 /* un-defense by tel controller */
#define STAT_ALARM 5 /* alarm by tel controller */
#define STAT_DOORR 6 /* door alarm */
#define STAT_INFRA 7 /* infrared alarm */
#define STAT_BYWEB 8 /* defense from website */
#define STAT_UNWEB 9 /* un-defense from website */
#define STAT_PHONE 10 /* defense from phone */
#define STAT_UNPHO 11 /* un-defense from phone */
#define STAT_OFFLI 12 /* offline */
#define STAT_OTHER 13 /* other... */


#define DEVID_NUM_ALL 12  /* device identity numer length */
#define DEVID_NUM 3  /* effective UNIQUE ID bytes */
#define PROTO_DEVI 3 /* id begin, 3~6 bytes */
#define PROTO_SPEC 11 /* device type */
#define PROTO_TYPE 15
#define PROTO_DATA 16
#define PROTO_LENG 17
#define PROTO_LENG_TMP 52


/* some tiny function */

#ifndef min
#define min(A, B) ((A) < (B) ? (A) : (B))
#endif

#ifndef max
#define max(A, B) ((A) > (B) ? (A) : (B))
#endif

#define minsize(A, B) (sizeof(A) < sizeof(B) ? sizeof(A) : sizeof(B))
#define maxsize(A, B) (sizeof(A) > sizeof(B) ? sizeof(A) : sizeof(B))

#ifndef isblank
#define isblank(c) ((c) == ' ' || (c) == '\t' || (c) == '\n' || (c) == '\r')
#endif

#ifndef isdigit
#define isdigit(c) ((c) <= '9' && (c) >= '0')
#endif

#ifndef isalpha
#define isalpha(c) ((c) <= 'z' && (c) >= 'a' || (c) <= 'Z' && (c) >= 'A')
#endif

#ifndef upper
#define upper(c) ((c) <= 'z' && (c) >= 'a' ? (c) - 'a' + 'A' : (c))
#endif

#ifndef lower
#define lower(c) ((c) <= 'Z' && (c) >= 'A' ? (c) - 'A' + 'a' : (c))
#endif


/* struct define */

typedef short bool;
typedef unsigned int uint32_t;
typedef unsigned short uint16_t;
typedef unsigned long devid_t;
typedef int stat_t;
typedef int spec_t;
typedef unsigned long ip_t;
typedef unsigned int disp_t;
typedef unsigned int uid_t;
typedef int locked_t;
typedef pthread_mutex_t mutex_t;

typedef struct {
	devid_t devid;
} KEY;

typedef struct {
	ip_t ip;
	stat_t stat;
	int up_time;
} VALUE;

typedef struct {
	char alarm;  /* buffer[PROTO_DATA] */
	char phone[PHONE_SIZE];
} PHONE_PAIR;

typedef struct {
	char db_host[MAXLEN];
	char db_user[MAXLEN];
	char db_pswd[MAXLEN];
	char db_name[MAXLEN];
	unsigned int serv_port;
} CONFIG;

typedef struct {
	char hostname[MAXLEN];
	char username[MAXLEN];
	char password[MAXLEN];
	char database[MAXLEN];
} DB_CONN;

typedef struct {
	MYSQL *conn;
	
	MYSQL_STMT *insert_stmt;
	ip_t insert_ip;
	spec_t insert_spec;
	devid_t insert_devid;
	stat_t insert_stat;
	
	MYSQL_STMT *update_stmt;
	ip_t update_ip;
	devid_t update_devid;
	stat_t update_stat;
	
	/* Obtain mobile phone from devid */
	MYSQL_STMT *select_stmt;
	devid_t select_devid;

	/* Below forr gDBQ_Defen */
	/* get devid from mobile phone */
	MYSQL_STMT *sel_devid_stmt;
	char sel_devid_phone[PHONE_SIZE];
	unsigned long sel_devid_phone_len; /* assoicate */
	
	/* get stat from devid */
	MYSQL_STMT *sel_stat_stmt;
	devid_t sel_stat_devid;

	/* get IP from devid */
	MYSQL_STMT *sel_ip_stmt;
	devid_t sel_ip_devid;

	/* update status by devid */
	MYSQL_STMT *update_stat_stmt;
	stat_t update_stat_stat;
	devid_t update_stat_devid;

	/* authorization */
	MYSQL_STMT *auth_stmt;
	devid_t auth_devid;

	mutex_t *mutex;
} DB_QUERY;

typedef struct {
    int nYear; /* From  2001 */
    int nMon;
    int nDay;
    int nHour; /* From 0 to 23 */
    int nMin;
    int nSec;
} TIMESTRU;

typedef	void	Sigfunc(int);	/* for signal handlers */

#define VERIFY(b)		err_log((errno = 0) || (b), NULL, __FILE__, __LINE__)
#define VERIFYEXT(b,c)	err_log((errno = 0) || (b), c, __FILE__, __LINE__)
#define ASSERT(b)		VERIFY(b)
#define ASSERTEXT(b, c)	if (VERIFY(b)) ; else return(c);

/* debug.c */
/*
int PrintLog(FILE* pfile, const char * pformat, ...);
int PrintTraceLog(const char* pformat, ...);
int PrintHexLog(FILE* pfile, void * pData, int nSize);
int PrintTraceHexLog(void * pData, int nSize);
int Verify(int bStatus, const char* szBuf, const char* szFile, int nLine);
TIMESTRU GetTime();
TIMESTRU GetOffsetTime(TIMESTRU timestru, int nOffsetSec);
*/
/* error.c */
void err_dump(const char *, ...);
void err_msg(const char *, ...);
void err_quit(const char *, ...);
void err_ret(const char *, ...);
void err_sys(const char *, ...);
int err_log(int status, const char* buf, const char* file, int line);
/* wrapsock.c */
int		 Accept(int, SA *, socklen_t *);
void	 Bind(int, const SA *, socklen_t);
void	 Connect(int, const SA *, socklen_t);
void	 Getpeername(int, SA *, socklen_t *);
void	 Getsockname(int, SA *, socklen_t *);
void	 Getsockopt(int, int, int, void *, socklen_t *);
int		 Isfdtype(int, int);
void	 Listen(int, int);
#ifdef	HAVE_POLL
int		 Poll(struct pollfd *, unsigned long, int);
#endif
ssize_t	 Readline(int, void *, size_t);
ssize_t	 Readn(int, void *, size_t);
ssize_t	 Recv(int, void *, size_t, int);
ssize_t	 Recvfrom(int, void *, size_t, int, SA *, socklen_t *);
ssize_t	 Recvmsg(int, struct msghdr *, int);
int		 Select(int, fd_set *, fd_set *, fd_set *, struct timeval *);
void	 Send(int, const void *, size_t, int);
int		 Sendto(int, const void *, size_t, int, const SA *, socklen_t);
void	 Sendmsg(int, const struct msghdr *, int);
void	 Setsockopt(int, int, int, const void *, socklen_t);
void	 Shutdown(int, int);
int		 Sockatmark(int);
int		 Socket(int, int, int);
void	 Socketpair(int, int, int, int *);
void	 Writen(int, void *, size_t);

/* signal.c */
Sigfunc *Signal(int, Sigfunc *);
void sig_chld(int signo);
void sig_engine();
void sig_dispatcher();

/* config.c */
int get_config(char *filepath, char *cate, char *name, char *value);
int get_db_config(char *filepath, DB_CONN *dbc);

/* db.c */
int db_init(DB_QUERY *dbq, DB_CONN *dbc);
int db_stmt_prepare(DB_QUERY *dbq);
int db_stmt_release(DB_QUERY *dbq);
int db_stmt_query(MYSQL_STMT *stmt);
int db_insert_status(DB_CONN *dbc, char *devid, char *ip, int *stat);
/* int db_stmt_phone(DB_CONN *dbc, devid_t devid, char *phone); */
int db_stmt_phone(DB_QUERY *dbq, char *phone);
devid_t db_stmt_sel_devid(DB_QUERY *dbq);
stat_t db_stmt_sel_stat(DB_QUERY *dbq);
ip_t db_stmt_sel_ip(DB_QUERY *dbq);
int db_query_phone(DB_CONN *dbc, devid_t devid, char *phone);

/* func.c */
char * trim(char* dstr);
void print_hex(char *hex, int len);
void cvt_devid(char *devid, char *devid_f);
void cvt_iddev(char *devid_f, char *devid);
devid_t cvt_id(char *devid);
void cvt_di(devid_t id, char *devid);
ip_t cvt_ip(char *ip_str);
void cvt_pi(ip_t ip, char *ip_str);
int get_host_addr(char *ip_addr);
stat_t get_stat(char *buff);
void set_stat(char *buff, char type, char data);
devid_t get_devid(char *buff);
spec_t get_spec(char *buff);

/* heart.c */
int equal_keys(void *k1, void *k2);
uint32_t hash_from_key(void *ky);
int Heart();
int push_heart(devid_t devid);

/* defense.c */
int ws_alarm(PHONE_PAIR *pp);
int ws_alarm_recv(PHONE_PAIR **pp, int max);
void alarm_user_thread(PHONE_PAIR *pp);
void defense_run();
void Defense();

/* server.c */
void Server();
int push_hash(KEY *k, VALUE *v,  VALUE *lv);

/* mutex.c */
mutex_t *mutex_create(int recursive);
void mutex_destroy(mutex_t *mutex);
void mutex_lock(mutex_t *mutex);
void mutex_unlock(mutex_t *mutex);

/* auth.c */
bool auth_devid(devid_t devid);

/* ##########################Global Variable############################# */
struct hashtable *gHash;
struct hashtable_itr *gHitr;
devid_t *gDevList;
DB_QUERY gDBQ;
DB_QUERY gDBQ_Defen; /* forr Defense() */
DB_CONN gDBConn;
disp_t gDispatcher;
/* unsigned long gAddr; */
int daemon_proc;		/* set nonzero by daemon_init() */

#endif /* _COMMON_H */

